#pragma once

#include "stdafx.h"
#include "ted.h"
//#include <typeinfo>

#define DEFAULT_BUF_SIZE 128

namespace TED {
/**
	@author ncanis
	@brief 버퍼 클래스. 모든 Packet 수신/전송은 이 데이터를 가지고 수행한다.
*/
//template <size_t buffer_size> class IoBuffer {
class IoBuffer {
private:
	INT capacity; //담을수 있는 최대 메모리 길이
	INT position; // 현재 포인터 위치
	INT limit; // Buffer의 이용한계
	INT mark; //마킹 위치
	BYTE* buf;

	void SetAutoExpand(UINT32 size); // 자동으로 현재 주어진 버퍼를 확장한다.
	template <class T> IoBuffer& AddData(T* const t, INT32 size) {
		SetAutoExpand(size);
		CopyMemory(buf+position, t, size);
		this->position +=size;
		return *this;
	}

	template <class T> IoBuffer& GetData(T* const t, UINT32 size) {
		assert((unsigned int)(limit-position)>=size);
		CopyMemory(t, buf+position, size);
		this->position +=size;
		return *this;
	}

	// tostring overload
	// friend 외부에서 클래스의 private 멤버에 대해 접근을 허용을 하게 한다.
	friend std::ostream& operator<<(std::ostream&, IoBuffer*);
public:
	IoBuffer(INT capacity);
	virtual ~IoBuffer();
	//
	INT32 Position();
	INT32 Limit();
	BYTE* toBuf();
	IoBuffer& Slice(BYTE* const data, INT32 size); // 현재 Position 부터 limit까지 Slice하여 data로 전달한다.
	IoBuffer& Rewind(); // 맨처음으로 돌린다.
	IoBuffer& Mark(); // 현재 Position을 기억한다.
	IoBuffer& Reset(); // Mark한 Position으로 이동한다.
	IoBuffer& Flip(); // Position =0 으로, Limit를 현재 Position위치로 이동시킨다.
	void ToHexDump();
	void GetHexDump(TCHAR* const data, int size);

	// Add
	// Template class methods must be defined in the header file
	// @deprecated. (타입에 대한 직관성 부재)
//	template <class T> IoBuffer& Add(T t) {
//		INT length = sizeof(t);
//		SetAutoExpand(length);
//		CopyMemory(buf+position,  &t, length);
//		this->position +=length;
//		return this;
//	};

	IoBuffer& AddTChars(TCHAR* const, INT size=(-1));
	IoBuffer& AddBytes(BYTE* const, INT size=(-1));
	IoBuffer& AddByte(const BYTE data);
	IoBuffer& AddInt16(const INT16 data);
	IoBuffer& AddInt32(const INT32 data);
	IoBuffer& AddInt64(const INT64 data);
	IoBuffer& AddFloat(const FLOAT data);

	///////////////////////////////////////////////////////////////////////////////
	// Get (Call by value)
	template <class T> IoBuffer& Get(T* const t) {
		INT size = sizeof(t);
		CopyMemory(t, buf+position, size);
		this->position += size;
		return this;
	};

	IoBuffer& GetTChars(TCHAR* const tc);
	IoBuffer& GetBytes(BYTE* const tc, INT size);
	BYTE GetByte();
	INT16 GetInt16();
	INT32 GetInt32();
	INT64 GetInt64();
	FLOAT GetFloat();
};

} /* namespace ted */
